import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import re
import os

from config_loader import load_global_config, get_full_config_path, get_global_config


class NotificationConfigFrame(ttk.Frame):
    """
    通知配置界面框架（合并邮件和音频配置）
    """

    def __init__(self, parent, config_file_path="../config/config.toml"):
        super().__init__(parent)
        self.config_file_path = config_file_path
        self.config = load_global_config(config_file_path)
        self.setup_ui()
        # 在UI初始化完成后加载配置
        self.load_config()

    def setup_ui(self):
        """
        设置界面元素
        """
        # 创建主框架
        main_frame = ttk.Frame(self, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 通知配置标题
        notification_title = ttk.Label(main_frame, text="通知设置", font=("Arial", 14, "bold"))
        notification_title.grid(row=0, column=0, columnspan=3, pady=(0, 10), sticky=tk.W)

        # 邮件通知启用开关
        self.email_enabled_var = tk.BooleanVar()
        email_enabled_check = ttk.Checkbutton(main_frame, text="启用邮件通知", variable=self.email_enabled_var)
        email_enabled_check.grid(row=1, column=0, sticky=tk.W, pady=5)

        # 邮件配置子框架
        self.email_frame = ttk.LabelFrame(main_frame, text="邮件配置", padding="10")
        self.email_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10))

        # SMTP服务器地址
        ttk.Label(self.email_frame, text="SMTP服务器:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.email_host_entry = ttk.Entry(self.email_frame, width=30)
        self.email_host_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))

        # 端口
        ttk.Label(self.email_frame, text="端口:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.email_port_entry = ttk.Entry(self.email_frame, width=30)
        self.email_port_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))

        # 用户名（邮箱地址）
        ttk.Label(self.email_frame, text="用户名:").grid(row=2, column=0, sticky=tk.W, pady=5)
        self.email_username_entry = ttk.Entry(self.email_frame, width=30)
        self.email_username_entry.grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))

        # 密码
        ttk.Label(self.email_frame, text="密码:").grid(row=3, column=0, sticky=tk.W, pady=5)
        self.email_password_entry = ttk.Entry(self.email_frame, width=30, show="*")
        self.email_password_entry.grid(row=3, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))

        # 使用TLS
        self.email_use_tls_var = tk.BooleanVar()
        self.email_use_tls_check = ttk.Checkbutton(self.email_frame, text="使用TLS", variable=self.email_use_tls_var)
        self.email_use_tls_check.grid(row=4, column=1, sticky=tk.W, pady=5, padx=(10, 0))

        # 收件人列表输入框
        ttk.Label(self.email_frame, text="收件人:").grid(row=5, column=0, sticky=tk.W, pady=5)
        self.email_recipients_entry = ttk.Entry(self.email_frame, width=30)
        self.email_recipients_entry.grid(row=5, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))

        # 测试邮件按钮
        test_email_button = ttk.Button(self.email_frame, text="测试邮件", command=self.test_email)
        test_email_button.grid(row=6, column=1, sticky=tk.W, pady=5, padx=(10, 0))

        # 音频通知启用开关
        self.audio_enabled_var = tk.BooleanVar()
        audio_enabled_check = ttk.Checkbutton(main_frame, text="启用音频通知", variable=self.audio_enabled_var)
        audio_enabled_check.grid(row=3, column=0, sticky=tk.W, pady=5)

        # 音频配置子框架
        self.audio_frame = ttk.LabelFrame(main_frame, text="音频配置", padding="10")
        self.audio_frame.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10))

        # 默认音频文件显示
        ttk.Label(self.audio_frame, text="默认音频文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
        default_file_path = os.path.join("static", "audio", "1.mp3")
        self.default_file_label = ttk.Label(self.audio_frame, text=default_file_path)
        self.default_file_label.grid(row=0, column=1, sticky=tk.W, padx=(10, 0))

        # 自定义音频文件路径设置
        ttk.Label(self.audio_frame, text="自定义音频文件:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.sound_file_var = tk.StringVar()
        self.sound_file_entry = ttk.Entry(self.audio_frame, width=30, textvariable=self.sound_file_var)
        self.sound_file_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))

        # 文件选择按钮
        self.browse_button = ttk.Button(self.audio_frame, text="浏览...", command=self.browse_sound_file)
        self.browse_button.grid(row=1, column=2, padx=(5, 0))

        ttk.Label(self.audio_frame, text="(留空则使用默认音频文件)", foreground="gray").grid(row=2, column=1,
                                                                                             sticky=tk.W, padx=(10, 0))

        # 测试播放按钮
        test_audio_button = ttk.Button(self.audio_frame, text="测试播放", command=self.test_audio)
        test_audio_button.grid(row=3, column=1, sticky=tk.W, pady=5, padx=(10, 0))

        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=5, column=0, columnspan=3, pady=20)

        # 保存按钮
        save_button = ttk.Button(button_frame, text="保存配置", command=self.save_config)
        save_button.pack(side=tk.LEFT, padx=(0, 10))

        # 重置按钮
        reset_button = ttk.Button(button_frame, text="重置", command=self.load_config)
        reset_button.pack(side=tk.LEFT, padx=(0, 10))

        # 设置列权重
        self.columnconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        self.email_frame.columnconfigure(1, weight=1)
        self.audio_frame.columnconfigure(1, weight=1)

    def browse_sound_file(self):
        """
        浏览并选择音频文件
        """
        file_path = filedialog.askopenfilename(
            title="选择音频文件",
            filetypes=[
                ("音频文件", "*.wav *.mp3 *.ogg *.flac"),
                ("WAV文件", "*.wav"),
                ("MP3文件", "*.mp3"),
                ("所有文件", "*.*")
            ]
        )

        if file_path:
            self.sound_file_var.set(file_path)

    def load_config(self):
        """
        从配置文件加载通知配置到界面
        """
        # 加载邮件配置 (现在只从 notification 节获取)
        email_config = self.config.get_email_config()

        self.email_host_entry.delete(0, tk.END)
        self.email_host_entry.insert(0, email_config.get('host', ''))

        self.email_port_entry.delete(0, tk.END)
        self.email_port_entry.insert(0, str(email_config.get('port', '')))

        self.email_username_entry.delete(0, tk.END)
        self.email_username_entry.insert(0, email_config.get('username', ''))

        self.email_password_entry.delete(0, tk.END)
        self.email_password_entry.insert(0, email_config.get('password', ''))

        self.email_use_tls_var.set(email_config.get('use_tls', True))
        self.email_recipients_entry.delete(0, tk.END)
        self.email_recipients_entry.insert(0, ",".join( email_config.get('recipients', [])))

        # 默认启用邮件通知 (如果配置存在)
        # 如果 notification.email_enabled 明确为 False，则关闭；否则如果 host 有值则开启
        email_enabled_from_config = email_config.get('enabled')
        if email_enabled_from_config is not None:
            self.email_enabled_var.set(email_enabled_from_config)
        else:
            self.email_enabled_var.set(bool(email_config.get('host', '')))

        # 加载音频配置
        audio_config = self.config.get_audio_config()
        audio_enabled_from_config = audio_config.get('enabled')
        if audio_enabled_from_config is not None:
            self.audio_enabled_var.set(audio_enabled_from_config)
        else:
            self.audio_enabled_var.set(True)  # 默认开启

        self.sound_file_var.set(audio_config.get('sound_file', ''))

    def save_config(self):
        """
        保存界面中的配置到文件
        """
        # 验证邮箱地址格式（如果启用了邮件通知）
        if self.email_enabled_var.get():
            if not self._validate_email(self.email_username_entry.get()):
                messagebox.showerror("配置错误", "请输入有效的邮箱地址")
                return

            # 验证端口格式
            try:
                port = int(self.email_port_entry.get())
                if port < 1 or port > 65535:
                    raise ValueError("端口必须在1-65535之间")
            except ValueError:
                messagebox.showerror("配置错误", "请输入有效的端口号(1-65535)")
                return

        # 写入配置文件
        try:
            config = self.config
            # 1. 保存通知配置
            email_config = config.get_email_config()
            email_config['host'] = self.email_host_entry.get()
            email_config['port'] = int(self.email_port_entry.get())
            email_config['use_tls'] = self.email_use_tls_var.get()
            email_config['username'] = self.email_username_entry.get()
            email_config['password'] = self.email_password_entry.get()
            email_config['recipients'] = self.email_recipients_entry.get().split(",")
            email_config['enabled'] = self.email_enabled_var.get()

            config.set_email_config(email_config)
            self.config.save(self.config_file_path)
            messagebox.showinfo("保存成功", "配置已成功保存")
            # 重新加载配置
            self.config = load_global_config(self.config_file_path)
        except Exception as e:
            messagebox.showerror("保存失败", f"保存配置时出错: {str(e)}")



    def load_config(self):
        """
        从配置文件加载通知配置到界面
        """
        # 加载邮件配置 (现在只从 notification 节获取)
        email_config = self.config.get_email_config()

        self.email_host_entry.delete(0, tk.END)
        self.email_host_entry.insert(0, email_config.get('host', ''))

        self.email_port_entry.delete(0, tk.END)
        self.email_port_entry.insert(0, str(email_config.get('port', '')))

        self.email_username_entry.delete(0, tk.END)
        self.email_username_entry.insert(0, email_config.get('username', ''))

        self.email_password_entry.delete(0, tk.END)
        self.email_password_entry.insert(0, email_config.get('password', ''))

        self.email_use_tls_var.set(email_config.get('use_tls', True))
        self.email_recipients_entry.delete(0, tk.END)
        self.email_recipients_entry.insert(0, ",".join(email_config.get('recipients', [])))

        # 默认启用邮件通知 (如果配置存在)
        # 如果 notification.email_enabled 明确为 False，则关闭；否则如果 host 有值则开启
        email_enabled_from_config = email_config.get('enabled')
        if email_enabled_from_config is not None:
            self.email_enabled_var.set(email_enabled_from_config)
        else:
            self.email_enabled_var.set(bool(email_config.get('host', '')))

        # 加载音频配置
        audio_config = self.config.get_audio_config()
        audio_enabled_from_config = audio_config.get('enabled')
        if audio_enabled_from_config is not None:
            self.audio_enabled_var.set(audio_enabled_from_config)
        else:
            self.audio_enabled_var.set(True)  # 默认开启

        self.sound_file_var.set(audio_config.get('sound_file', ''))


    def test_email(self):
        """
        测试邮件配置
        """
        if not self.email_enabled_var.get():
            messagebox.showwarning("测试失败", "邮件通知未启用")
            return

        # 验证配置
        if not self._validate_email(self.email_username_entry.get()):
            messagebox.showerror("配置错误", "请输入有效的邮箱地址")
            return

        try:
            port = int(self.email_port_entry.get())
            if port < 1 or port > 65535:
                raise ValueError("端口必须在1-65535之间")
        except ValueError:
            messagebox.showerror("配置错误", "请输入有效的端口号(1-65535)")
            return

        host = self.email_host_entry.get().strip()
        if not host:
            messagebox.showerror("配置错误", "请输入SMTP服务器地址")
            return

        username = self.email_username_entry.get().strip()
        password = self.email_password_entry.get()

        # 检查是否有收件人地址
        recipients_str = self.email_recipients_entry.get().strip()
        if not recipients_str:
            messagebox.showwarning("收件人为空", "请输入收件人邮箱地址以发送测试邮件")
            return

        if not self._validate_email(recipients_str):
            messagebox.showerror("邮箱格式错误", "请输入有效的收件人邮箱地址，多个邮箱请用逗号分隔")
            return
        recipients = [e.strip() for e in recipients_str.split(',') if e.strip()]

        # 尝试连接SMTP服务器并发送测试邮件
        try:
            # 创建邮件发送实例
            from notify.email_sender import EmailSender
            sender = EmailSender(host, port, username, password, self.email_use_tls_var.get())

            # 生成随机标题和内容
            subject = self._generate_random_subject()
            content = self._generate_random_content()

            # 发送测试邮件
            if sender.connect():
                result = sender.send(subject, content, recipients)
                sender.disconnect()

                if result:
                    messagebox.showinfo("测试成功", f"测试邮件已成功发送到 {recipients_str}")
                else:
                    messagebox.showerror("发送失败", "邮件配置测试通过但发送测试邮件失败")
            else:
                messagebox.showerror("连接失败", "无法连接到SMTP服务器，请检查配置")

        except Exception as e:
            messagebox.showerror("测试失败", f"测试过程中发生未知错误: {str(e)}")


    def test_audio(self):
        """
        测试播放用户选择的音频文件
        """
        if not self.audio_enabled_var.get():
            messagebox.showwarning("测试失败", "音频通知未启用")
            return

        try:
            # 获取用户选择的音频文件
            sound_file = self.sound_file_var.get().strip()

            # 如果没有选择音频文件，使用默认文件
            if not sound_file:
                sound_file = os.path.join("static", "audio", "1.mp3")

            # 检查文件是否存在
            if not self._validate_sound_file(sound_file):
                messagebox.showerror("配置错误", f"指定的音频文件不存在或无效: {sound_file}")
                return

            # 播放音频
            from notify.audio_sender import AudioSender
            audio_sender = AudioSender()

            if audio_sender.connect():
                result = audio_sender.send("测试音频", "音频配置测试", [], sound_file=sound_file)
                audio_sender.disconnect()

                if result:
                    messagebox.showinfo("测试成功", f" 音频播放成功\n文件: {sound_file}")
                else:
                    messagebox.showerror("测试失败", f"音频播放失败\n文件: {sound_file}")
            else:
                messagebox.showerror("测试失败", "无法连接到音频服务")

        except Exception as e:
            messagebox.showerror("测试失败", f"测试过程中发生未知错误: {str(e)}")


    def _validate_email(self, email_string):
        """
        验证邮箱地址格式，支持逗号分隔的多个邮箱

        :param email_string: 邮箱地址字符串，可能包含多个邮箱，用逗号分隔
        :return: 格式是否正确
        """
        if not email_string.strip():  # 允许为空
            return True
        emails = [e.strip() for e in email_string.split(',') if e.strip()]
        if not emails:
            return False
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        for email in emails:
            if not re.match(pattern, email):
                return False
        return True


    def _validate_sound_file(self, sound_file):
        """
        验证音频文件是否存在且有效

        :param sound_file: 音频文件路径
        :return: 文件是否有效
        """
        return os.path.exists(sound_file) and os.path.isfile(sound_file)


    def _generate_random_subject(self):
        """
        生成随机邮件主题

        :return: 随机邮件主题
        """
        import random
        import string
        prefixes = ["系统测试", "配置验证", "功能检查", "服务测试", "邮件确认"]
        suffixes = ["通知", "报告", "消息", "提醒", "状态"]
        random_prefix = random.choice(prefixes)
        random_suffix = random.choice(suffixes)
        random_num = ''.join(random.choices(string.digits, k=3))
        return f"{random_prefix}{random_suffix}[{random_num}]"


    def _generate_random_content(self):
        """
        生成随机邮件内容

        :return: 随机邮件内容
        """
        import random
        greetings = ["您好！", "Hello!", "Hi there!", "尊敬的用户，"]
        bodies = [
            "这是一封测试邮件，用于验证您的邮件配置是否正确。",
            "系统正在进行邮件功能测试，请忽略此邮件。",
            "恭喜！您收到了一封来自系统配置的测试邮件。",
            "如果您收到此邮件，说明您的邮件配置已经生效。"
        ]
        endings = [
            "\n\n祝好！\n系统管理员",
            "\n\n此邮件为系统自动发送，请勿回复。",
            "\n\n谢谢！\n技术支持团队",
            "\n\n--\n测试系统"
        ]

        greeting = random.choice(greetings)
        body = random.choice(bodies)
        ending = random.choice(endings)

        return f"{greeting}\n\n{body}\n{ending}"
